﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SmallERP.MODEL.FoundationModel;
using SmallERP.MODEL.PBModel;
using SmallERP.DAL;
using System.Drawing;
using System.Threading;

namespace SmallERP.Bll.PinBan
{
    /// <summary>
    /// 当全自动拼板的结果，则需要向界面显示的相关信息的事件
    /// </summary>
    /// <param name="result">0：代表成功，-1：出错</param>
    /// <param name="wrate"></param>
    /// <param name="Pnum"></param>
    /// <param name="overPnum"></param>
    public delegate void GetFAutoPBResult(int result, float wrate, int Pnum, int overPnum, string msg);
    public class FullAutoPBBLL
    {

        const int TEMPLATENUM = 10000;
        const float PIPEIPER = 0.9F;//全自动匹配的比例
        const int BARCODEWIDTH = 25;//条码点25个象素点宽

        public event GetFAutoPBResult AutoPBResultEvent;

        /// <summary>
        /// 是否暂停全自动拼板
        /// </summary>
        public bool IsStop { get; set; }
        private string _addr;
        private int _port;
        private OrderBLL orderBll;
        public FullAutoPBBLL(string addr,int port)
        {
            _addr = addr;
            _port = port;
            orderBll = new OrderBLL(addr, port);
        }

        /// <summary>
        /// 全自动拼板
        /// </summary>
        /// <param name="rate"></param>
        /// <param name="boardTemplate_Info"></param>
        /// <param name="printer_info"></param>
        /// <returns></returns>
        public int FAUTOPB(float rate, BoardTemplate_Info boardTemplate_Info, Printer_info printer_info)
        {
            int result = 0;
            //List<PhotoInfo_PB> AllPhotoList, PriorityPhotoList;
            //List<AutoBoardTemplate> templateList;
            //GetSuitTemplate(boardTemplate_Info, out templateList);
            //GetPartPBedPhotos(boardTemplate_Info, printer_info, out AllPhotoList, out PriorityPhotoList);

            ////OrderBLL orderBll = new OrderBLL();

            ////试过多少种模板,即不成功的次数
            //int tryTemplateCount = 0;


            //while (!IsStop)
            //{
            //    if (tryTemplateCount >= templateList.Count)
            //    {
            //        IsStop = true;
            //        AutoPBTemplateBLL.ChangeUseNum(templateList);
            //        //AutoPBResultEvent(2, 0, 0, 0, "剩余的板无法全自动拼，请手动拼板！");
            //        //return result;
            //        break;
            //    }
            //    #region 不停地用模板去套照片
            //    foreach (var t in templateList)
            //    {

            //        if (!t.AutoBoardDetail.IsLoaded)
            //        {
            //            t.AutoBoardDetail.Load();
            //        }
            //        List<PhotoInfo_PB> resultList = new List<PhotoInfo_PB>();
            //        List<PhotoInfo_PB> TempPBTartGetList = new List<PhotoInfo_PB>();//用于查找照片的目标列表
            //        foreach (var tdetail in t.AutoBoardDetail.ToList())
            //        {
            //            PhotoInfo_PB pi = GetSuitPicList(ref PriorityPhotoList, ref AllPhotoList, tdetail, boardTemplate_Info, printer_info, resultList);

            //            if (pi != null)//找到了一张
            //            {
            //                resultList.Add(pi);
            //            }
            //            else
            //            {
            //                //只在这个模板中的任意一张没有找到就试下一个模板//并恢复已用过的照片ISWHIRL属性
            //                foreach (var pit in resultList)
            //                {
            //                    pit.IsWhirl = false;
            //                    pit.IsAutoPB = false;
            //                    pit.Location = new Point(0, 0);
            //                }
            //                resultList.Clear();
            //                tryTemplateCount++;
            //                break;
            //            }
            //        }

            //        if (resultList.Count > 0)
            //        {
            //            tryTemplateCount = 0;

            //            #region 按要求匹配成功

            //            //则表示自动拼板成功一个，将结果数据添加到BOARD表中
            //            int MaxX = 0;
            //            float wraste = GetRealWraste(resultList, Convert.ToInt32(t.Height * printer_info.PDPI), out MaxX);
            //            if (wraste <= rate)
            //            {
            //                int createBigPicResult = orderBll.CreateBoard(resultList, boardTemplate_Info, printer_info, wraste, MaxX, false);
            //                if (createBigPicResult == 0)//生成大图成功
            //                {
            //                    t.UseNUM++;
            //                    AutoPBResultEvent(0, wraste, resultList.Count, AllPhotoList.Count(p => !p.IsInBoard), "拼板成功");
            //                    resultList.Clear();
            //                }
            //                else
            //                {
            //                    tryTemplateCount++;
            //                    string errMsg = "向数据库写入数据时出错";
            //                    if (createBigPicResult==-2)
            //                    {
            //                        errMsg = "服务器加密狗信息出错！";
            //                    }
            //                    AutoPBResultEvent(2, 0, 0, 0, errMsg);
            //                    break;
            //                }

            //            }
            //            else//浪费未达到指定的要求,继续试一下模板
            //            {
            //                foreach (var pit in resultList)
            //                {
            //                    pit.IsWhirl = false;
            //                    pit.IsAutoPB = false;
            //                    pit.Location = new Point(0, 0);
            //                }
            //                resultList.Clear();
            //                continue;
            //            }
            //            #endregion
            //        }

            //    }

            //    #endregion 不停地用模板去套照片

            //    Thread.Sleep(1000);//每拼完一次拼就暂停1秒
            //}
            //AutoPBTemplateBLL.ChangeUseNum(templateList);
            //if (AllPhotoList.Count(p => !p.IsAutoPB) > 0)//还剩余的照片没有拍，则使用“半自动用的拼板算法进行拼板”
            //{
            //    OtherFullAutoPB(AllPhotoList, boardTemplate_Info, printer_info, rate);
            //}

            //AutoPBResultEvent(10, 0, 0, 0, "停止成功");

            return result;
        }


        /// <summary>
        /// 用半自动拼板算法来进行全自动拼板
        /// </summary>
        private void OtherFullAutoPB(List<PhotoInfo_PB> sourcePList, BoardTemplate_Info boardTemplate_Info, Printer_info printer_info, float rate)
        {
            //OrderBLL orderBll = new OrderBLL();
            List<PhotoInfo_PB> resultList = orderBll.AutoPinS(sourcePList, boardTemplate_Info, printer_info);
            if (resultList.Count > 0)
            {
                //则表示自动拼板成功一个，将结果数据添加到BOARD表中
                int MaxX = 0;
                float wraste = GetRealWraste(resultList, Convert.ToInt32(boardTemplate_Info.Height * printer_info.PDPI), out MaxX);
                AutoPBResultEvent(7, wraste, 0, 0, "向数据库写入数据时出错");
                if (wraste <= rate)
                {
                    int createBigPicResult = orderBll.CreateBoard(resultList, boardTemplate_Info, printer_info, wraste, MaxX, true);
                    if (createBigPicResult == 0)//生成大图成功
                    {
                        AutoPBResultEvent(0, wraste, resultList.Count, sourcePList.Count(p => !p.IsInBoard), "拼板成功");
                        sourcePList = sourcePList.Where(p => !p.IsInBoard).ToList();
                        sourcePList.ForEach(p => p.IsAutoPB = false);
                    }
                    else
                    {
                        string errMsg = "向数据库写入数据时出错";
                        if (createBigPicResult == -2)
                        {
                            errMsg = "服务器加密狗信息出错！";
                        }
                        AutoPBResultEvent(2, 0, 0, 0, errMsg);
                        return;
                    }
                    OtherFullAutoPB(sourcePList, boardTemplate_Info, printer_info, rate);
                }
                else//浪费未达到指定的要求
                {
                    if (orderBll.IsNewWhirl)
                    {
                        AutoPBResultEvent(2, 0, 0, 0, "剩余的板无法全自动拼，请手动拼板！");
                        return;
                    }
                    OtherFullAutoPB(sourcePList, boardTemplate_Info, printer_info, rate);
                }
            }

        }

        /// <summary>
        /// 找到合适的照片
        /// </summary>
        private PhotoInfo_PB GetSuitPic(ref List<PhotoInfo_PB> TempPBTartGetList, AutoBoardDetail tdetail)
        {
            #region 寻找匹配的照片
            PhotoInfo_PB pi = TempPBTartGetList.Find(p =>
            {
                if ((p.Photo_Base_Info.PixWidth == tdetail.Length && p.Photo_Base_Info.PixHeight == tdetail.Height) || (p.Photo_Base_Info.PixWidth == tdetail.Height && p.Photo_Base_Info.PixHeight == tdetail.Length))
                {
                    if (p.Photo_Base_Info.PixWidth == tdetail.Length && p.Photo_Base_Info.PixHeight == tdetail.Height)
                    {
                        p.IsWhirl = false;
                    }
                    else
                    {
                        p.IsWhirl = true;
                    }
                    p.IsAutoPB = true;
                    p.Location = new Point(tdetail.X, tdetail.Y);
                    return true;
                }
                else
                {
                    //只有一边匹配，另一边相差一定比例
                    if (p.Photo_Base_Info.PixHeight == tdetail.Length || p.Photo_Base_Info.PixHeight == tdetail.Height)
                    {

                        if (p.Photo_Base_Info.PixHeight == tdetail.Length)
                        {
                            if (p.Photo_Base_Info.PixWidth >= tdetail.Height * PIPEIPER && p.Photo_Base_Info.PixWidth <= tdetail.Height)
                            {
                                p.IsWhirl = true;
                                p.IsAutoPB = true;
                                p.Location = new Point(tdetail.X, tdetail.Y);
                                return true;
                            }
                            else
                            {
                                return false;
                            }

                        }
                        else//p.Photo_Base_Info.PixHeight == tdetail.Height
                        {
                            if (p.Photo_Base_Info.PixWidth >= tdetail.Length * PIPEIPER && p.Photo_Base_Info.PixWidth <= tdetail.Length)
                            {
                                p.IsWhirl = false;
                                p.IsAutoPB = true;
                                p.Location = new Point(tdetail.X, tdetail.Y);
                                return true;
                            }
                            else
                            {
                                return false;
                            }
                        }
                    }
                    else if (p.Photo_Base_Info.PixWidth == tdetail.Length || p.Photo_Base_Info.PixWidth == tdetail.Height)
                    {
                        if (p.Photo_Base_Info.PixWidth == tdetail.Length)
                        {
                            if (p.Photo_Base_Info.PixHeight >= tdetail.Height * PIPEIPER && p.Photo_Base_Info.PixHeight <= tdetail.Height)
                            {
                                p.IsWhirl = false;
                                p.IsAutoPB = true;
                                p.Location = new Point(tdetail.X, tdetail.Y);
                                return true;
                            }
                            else
                            {
                                return false;
                            }

                        }
                        else
                        {
                            if (p.Photo_Base_Info.PixHeight >= tdetail.Length * PIPEIPER && p.Photo_Base_Info.PixHeight <= tdetail.Length)
                            {
                                p.IsWhirl = true;
                                p.IsAutoPB = true;
                                p.Location = new Point(tdetail.X, tdetail.Y);
                                return true;
                            }
                            else
                            {
                                return false;
                            }
                        }
                    }
                    else//没有一边匹配的
                    {
                        return false;
                    }
                }
            });

            return pi;
            #endregion
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="PriorityPhotoList"></param>
        /// <param name="AllPhotoList"></param>
        /// <param name="tdetail"></param>
        /// <param name="boardTemplate_Info"></param>
        /// <param name="printer_info"></param>
        /// <param name="resultList">已经放在拼板结中的照片</param>
        /// <returns></returns>
        private PhotoInfo_PB GetSuitPicList(ref List<PhotoInfo_PB> PriorityPhotoList, ref List<PhotoInfo_PB> AllPhotoList, AutoBoardDetail tdetail, BoardTemplate_Info boardTemplate_Info, Printer_info printer_info, List<PhotoInfo_PB> resultList)
        {
            PhotoInfo_PB pi = new PhotoInfo_PB();

            List<PhotoInfo_PB> TempPBTartGetList = PriorityPhotoList.Where(p => !p.IsAutoPB).ToList();
            if (TempPBTartGetList.Count < 3)//如果待拼板的数量少于三个，就取所有的照片
            {
                TempPBTartGetList = AllPhotoList.Where(p => !p.IsAutoPB).ToList();

                if (TempPBTartGetList.Count < 10)//如果所有照片还少于10个,就从数据库中取
                {
                    GetPartPBedPhotos(boardTemplate_Info, printer_info, out AllPhotoList, out PriorityPhotoList);
                    //每次从数据库中取了新的之后需要放已放在排板结要集的照片排除掉
                    foreach (var PiEd in resultList)
                    {
                        AllPhotoList.FirstOrDefault(p => p.PhotoId == PiEd.PhotoId).IsAutoPB = true;
                    }
                    TempPBTartGetList = AllPhotoList.Where(p => !p.IsAutoPB).ToList();
                }
            }

            pi = GetSuitPic(ref TempPBTartGetList, tdetail);//先从加急中的照片去找
            if (pi == null)
            {
                AllPhotoList = AllPhotoList.Where(p => !p.IsAutoPB).ToList();
                pi = GetSuitPic(ref AllPhotoList, tdetail);//如果找不到就从所有照片去找
                if (pi == null)
                {
                    GetPartPBedPhotos(boardTemplate_Info, printer_info, out AllPhotoList, out PriorityPhotoList);
                    //每次从数据库中取了新的之后需要放已放在排板结要集的照片排除掉
                    foreach (var PiEd in resultList)
                    {
                        AllPhotoList.FirstOrDefault(p => p.PhotoId == PiEd.PhotoId).IsAutoPB = true;
                    }
                    AllPhotoList = AllPhotoList.Where(p => !p.IsAutoPB).ToList();

                    pi = GetSuitPic(ref AllPhotoList, tdetail);//如果还找不到就从数据库所有照片去找
                }
            }

            return pi;
        }


        /// <summary>
        /// 全自动拼板时得到真实的浪费量
        /// </summary>
        /// <param name="resultList"></param>
        /// <returns></returns>
        private float GetRealWraste(List<PhotoInfo_PB> resultP, int boardTemplateHeight, out int maxX)
        {
            maxX = 0;//某次拼板结果的最大X值
            float factRaste = 0;//某次拼板的实际浪费率
            int totalArea = 0;//某次拼板结果的大图的面积
            int factArea = 0;//此大图上有效照片的总面积


            maxX = resultP.Max(p => (p.Location.X + (p.IsWhirl ? p.Photo_Base_Info.PixHeight : p.Photo_Base_Info.PixWidth) + (p.BarCodeStatus == SmallERP.COM.Status.PhotoBarCodeStatus.RightOrLeft ? BARCODEWIDTH : 0)));//真实的相素
            totalArea = boardTemplateHeight * maxX;
            foreach (var pi in resultP)
            {
                if (pi.IsWhirl)
                {
                    switch (pi.BarCodeStatus)
                    {
                        case SmallERP.COM.Status.PhotoBarCodeStatus.RightOrLeft:
                            factArea += (pi.Photo_Base_Info.PixHeight + BARCODEWIDTH) * pi.Photo_Base_Info.PixWidth;
                            break;
                        case SmallERP.COM.Status.PhotoBarCodeStatus.TopOrBottom:
                            factArea += (pi.Photo_Base_Info.PixHeight) * (pi.Photo_Base_Info.PixWidth + BARCODEWIDTH);
                            break;
                        case SmallERP.COM.Status.PhotoBarCodeStatus.NoBarCode:
                            factArea += (pi.Photo_Base_Info.PixHeight) * (pi.Photo_Base_Info.PixWidth);
                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    switch (pi.BarCodeStatus)
                    {
                        case SmallERP.COM.Status.PhotoBarCodeStatus.RightOrLeft:
                            factArea += (pi.Photo_Base_Info.PixHeight) * (pi.Photo_Base_Info.PixWidth + BARCODEWIDTH);
                            break;
                        case SmallERP.COM.Status.PhotoBarCodeStatus.TopOrBottom:
                            factArea += (pi.Photo_Base_Info.PixHeight + BARCODEWIDTH) * (pi.Photo_Base_Info.PixWidth);
                            break;
                        case SmallERP.COM.Status.PhotoBarCodeStatus.NoBarCode:
                            factArea += (pi.Photo_Base_Info.PixHeight) * (pi.Photo_Base_Info.PixWidth);
                            break;
                        default:
                            break;
                    }
                }
            }


            factRaste = 1 - (float)factArea / totalArea;

            return factRaste;
        }


        /// <summary>
        /// 得到一定数量的模板，按浪费、使用次数排序
        /// </summary>
        /// <param name="boardTemplate_Info"></param>
        /// <param name="templateList"></param>
        public void GetSuitTemplate(BoardTemplate_Info boardTemplate_Info, out List<AutoBoardTemplate> templateList)
        {
            templateList = new List<AutoBoardTemplate>();
            using (smallerpDataContext db = new smallerpDataContext())
            {
                //主要是看高是否相等，还有就是长是否在模板的长度之内
                templateList = db.AutoBoardTemplate.Include("AutoBoardDetail").Where(bt => bt.Height == boardTemplate_Info.Height && bt.Length <= boardTemplate_Info.Length).Take(TEMPLATENUM).ToList().OrderBy(t => t.Waste).ThenByDescending(t => t.UseNUM).ToList();
            }
        }

        /// <summary>
        /// 根据模板得到部分被拼过的待拼板照片列表,先按加急级别排序再按PHOTOID排序
        /// </summary>
        /// <param name="boardTemplate_Info"></param>
        /// <returns></returns>
        private void GetPartPBedPhotos(BoardTemplate_Info boardTemplate_Info, Printer_info printerInfo, out List<PhotoInfo_PB> AllPhotoList, out List<PhotoInfo_PB> PriorityPhotoList)
        {
            AllPhotoList = new List<PhotoInfo_PB>();
            PriorityPhotoList = new List<PhotoInfo_PB>();
            //主要匹配纸、纸面、大小
            using (smallerpDataContext db = new smallerpDataContext())
            {
                int photoStatas = (int)SmallERP.COM.Status.PhotoStatus.WaitPB;
                int orderStatus = (int)SmallERP.COM.Status.OrderStatus.Doing;
                foreach (var pi in db.photoInfo.Where(p => p.orderInfo.Status == orderStatus && p.Status == photoStatas && p.orderInfo.PaperFaceId == boardTemplate_Info.PaperFaceId && p.orderInfo.PaperTypeId == boardTemplate_Info.PaperTypeId
                    && ((p.Width <= boardTemplate_Info.Length && p.Height <= boardTemplate_Info.Height) || (p.Width <= boardTemplate_Info.Height && p.Height <= boardTemplate_Info.Length))))
                {
                    PhotoInfo_PB pInfo = new PhotoInfo_PB();
                    pInfo.Photo_Base_Info = new Photo_Info()
                    {
                        Height = pi.Height,
                        IsClearBox = pi.IsClearBox,
                        IsReback = pi.IsReback,
                        PhotoId = pi.PhotoId,
                        SameFlagPhotoId = pi.SameFlagPhotoId,
                        Status = pi.Status,
                        PhotoName = pi.PhotoName,
                        PicPath = pi.PicPath,
                        PixHeight = Convert.ToInt32(pi.Height * printerInfo.PDPI),
                        PixWidth = Convert.ToInt32(pi.Width * printerInfo.PDPI),
                        Remark = pi.Remark,
                        Width = pi.Width
                    };

                    if (pi.IsReback || pi.IsClearBox)
                    {
                        PriorityPhotoList.Add(pInfo);
                    }
                    else
                    {
                        if (!pi.orderInfoReference.IsLoaded)
                        {
                            pi.orderInfoReference.Load();
                        }
                        if (!pi.orderInfo.photoInfo.IsLoaded)
                        {
                            pi.orderInfo.photoInfo.Load();
                        }
                        if (pi.orderInfo.photoInfo.ToList().Count(p => p.Status != photoStatas) > 0)//部分拼过板
                        {
                            PriorityPhotoList.Add(pInfo);
                        }
                    }

                    AllPhotoList.Add(pInfo);

                }

                //这里得到了所有照片
            }
        }
    }
}
